home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #11 / Amiga Plus CD - 2002 - No. 11.iso / Tools / Development / TinyGL / ami / content / ad709 / tinygl / src / clip.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-15  |  12.3 KB  |  531 lines

  1. /*$T clip.c GC 1.137 07/24/02 17:01:26 */
  2.  
  3. /*$6
  4.  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  5.  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  6.  */
  7.  
  8. #include "zgl.h"
  9.  
  10. /*
  11.  * fill triangle profile £
  12.  * #define PROFILE
  13.  */
  14. #define CLIP_XMIN    (1 << 0)
  15. #define CLIP_XMAX    (1 << 1)
  16. #define CLIP_YMIN    (1 << 2)
  17. #define CLIP_YMAX    (1 << 3)
  18. #define CLIP_ZMIN    (1 << 4)
  19. #define CLIP_ZMAX    (1 << 5)
  20.  
  21. /* */
  22.  
  23. void gl_transform_to_viewport(GLContext *c, GLVertex *v) {
  24.     float    winv;
  25.     /*~~~~~~~~~*/
  26.  
  27.     /* coordinates */
  28.     winv = 1.0 / v->pc.W;
  29.     v->zp.x = (int) (v->pc.X * winv * c->viewport.scale.X + c->viewport.trans.X);
  30.     v->zp.y = (int) (v->pc.Y * winv * c->viewport.scale.Y + c->viewport.trans.Y);
  31.     v->zp.z = (int) (v->pc.Z * winv * c->viewport.scale.Z + c->viewport.trans.Z);
  32.  
  33.     /* color */
  34.     if(c->lighting_enabled) {
  35.         v->zp.r = (int) (v->color.v[0] * (ZB_POINT_RED_MAX - ZB_POINT_RED_MIN) + ZB_POINT_RED_MIN);
  36.         v->zp.g = (int) (v->color.v[1] * (ZB_POINT_GREEN_MAX - ZB_POINT_GREEN_MIN) + ZB_POINT_GREEN_MIN);
  37.         v->zp.b = (int) (v->color.v[2] * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN) + ZB_POINT_BLUE_MIN);
  38.     }
  39.     else {
  40.         /* no need to convert to integer if no lighting : take current color */
  41.         v->zp.r = c->longcurrent_color[0];
  42.         v->zp.g = c->longcurrent_color[1];
  43.         v->zp.b = c->longcurrent_color[2];
  44.     }
  45.  
  46.     /* texture */
  47.     if(c->texture_2d_enabled) {
  48.         v->zp.s = (int) (v->tex_coord.X * (ZB_POINT_S_MAX - ZB_POINT_S_MIN) + ZB_POINT_S_MIN);
  49.         v->zp.t = (int) (v->tex_coord.Y * (ZB_POINT_T_MAX - ZB_POINT_T_MIN) + ZB_POINT_T_MIN);
  50.     }
  51. }
  52.  
  53. /* */
  54. static void gl_add_select1(GLContext *c, int z1, int z2, int z3) {
  55.     unsigned int    min, max;
  56.     min = max = z1;
  57.     if(z2 < min) {
  58.         min = z2;
  59.     }
  60.  
  61.     if(z3 < min) {
  62.         min = z3;
  63.     }
  64.  
  65.     if(z2 > max) {
  66.         max = z2;
  67.     }
  68.  
  69.     if(z3 > max) {
  70.         max = z3;
  71.     }
  72.  
  73.     gl_add_select(c, 0xffffffff - min, 0xffffffff - max);
  74. }
  75.  
  76. /* point */
  77. void gl_draw_point(GLContext *c, GLVertex *p0) {
  78.     if(p0->clip_code == 0) {
  79.         if(c->render_mode == GL_SELECT) {
  80.             gl_add_select(c, p0->zp.z, p0->zp.z);
  81.         }
  82.         else {
  83.             ZB_plot(c->zb, &p0->zp);
  84.         }
  85.     }
  86. }
  87.  
  88. /* line */
  89. static inline void interpolate(GLVertex *q, GLVertex *p0, GLVertex *p1, float t) {
  90.     q->pc.X = p0->pc.X + (p1->pc.X - p0->pc.X) * t;
  91.     q->pc.Y = p0->pc.Y + (p1->pc.Y - p0->pc.Y) * t;
  92.     q->pc.Z = p0->pc.Z + (p1->pc.Z - p0->pc.Z) * t;
  93.     q->pc.W = p0->pc.W + (p1->pc.W - p0->pc.W) * t;
  94.  
  95.     q->color.v[0] = p0->color.v[0] + (p1->color.v[0] - p0->color.v[0]) * t;
  96.     q->color.v[1] = p0->color.v[1] + (p1->color.v[1] - p0->color.v[1]) * t;
  97.     q->color.v[2] = p0->color.v[2] + (p1->color.v[2] - p0->color.v[2]) * t;
  98. }
  99.  
  100. /*
  101.  * Line Clipping £
  102.  * Line Clipping algorithm from 'Computer Graphics', Principles and Practice
  103.  */
  104. static inline int ClipLine1(float denom, float num, float *tmin, float *tmax) {
  105.     float    t;
  106.  
  107.     if(denom > 0) {
  108.         t = num / denom;
  109.         if(t > *tmax) {
  110.             return 0;
  111.         }
  112.  
  113.         if(t > *tmin) {
  114.             *tmin = t;
  115.         }
  116.     }
  117.     else if(denom < 0) {
  118.         t = num / denom;
  119.         if(t < *tmin) {
  120.             return 0;
  121.         }
  122.  
  123.         if(t < *tmax) {
  124.             *tmax = t;
  125.         }
  126.     }
  127.     else if(num > 0) {
  128.         return 0;
  129.     }
  130.  
  131.     return 1;
  132. }
  133.  
  134. /* */
  135. void gl_draw_line(GLContext *c, GLVertex *p1, GLVertex *p2) {
  136.     float        dx, dy, dz, dw, x1, y1, z1, w1;
  137.     float        tmin, tmax;
  138.     GLVertex    q1, q2;
  139.     int            cc1, cc2;
  140.  
  141.     cc1 = p1->clip_code;
  142.     cc2 = p2->clip_code;
  143.  
  144.     if((cc1 | cc2) == 0) {
  145.         if(c->render_mode == GL_SELECT) {
  146.             gl_add_select1(c, p1->zp.z, p2->zp.z, p2->zp.z);
  147.         }
  148.         else {
  149.             if(c->depth_test) {
  150.                 ZB_line_z(c->zb, &p1->zp, &p2->zp);
  151.             }
  152.             else {
  153.                 ZB_line(c->zb, &p1->zp, &p2->zp);
  154.             }
  155.         }
  156.     }
  157.     else if((cc1 & cc2) != 0) {
  158.         return;
  159.     }
  160.     else {
  161.         dx = p2->pc.X - p1->pc.X;
  162.         dy = p2->pc.Y - p1->pc.Y;
  163.         dz = p2->pc.Z - p1->pc.Z;
  164.         dw = p2->pc.W - p1->pc.W;
  165.         x1 = p1->pc.X;
  166.         y1 = p1->pc.Y;
  167.         z1 = p1->pc.Z;
  168.         w1 = p1->pc.W;
  169.  
  170.         tmin = 0;
  171.         tmax = 1;
  172.         if(ClipLine1(dx + dw, -x1 - w1, &tmin, &tmax) && ClipLine1(-dx + dw, x1 - w1, &tmin, &tmax) &&
  173.                    ClipLine1(dy + dw, -y1 - w1, &tmin, &tmax) &&
  174.                    ClipLine1(-dy + dw, y1 - w1, &tmin, &tmax) &&
  175.                    ClipLine1(dz + dw, -z1 - w1, &tmin, &tmax) && ClipLine1(-dz + dw, z1 - w1, &tmin, &tmax)) {
  176.             interpolate(&q1, p1, p2, tmin);
  177.             interpolate(&q2, p1, p2, tmax);
  178.             gl_transform_to_viewport(c, &q1);
  179.             gl_transform_to_viewport(c, &q2);
  180.  
  181.             if(c->depth_test) {
  182.                 ZB_line_z(c->zb, &q1.zp, &q2.zp);
  183.             }
  184.             else {
  185.                 ZB_line(c->zb, &q1.zp, &q2.zp);
  186.             }
  187.         }
  188.     }
  189. }
  190.  
  191. /*
  192.  =======================================================================================================================
  193.     triangle £
  194.     Clipping £
  195.     We clip the segment [a,b] against the 6 planes of the normal volume. We compute the point 'c' of intersection and
  196.     the value of the parameter 't' of the intersection if x=a+t(b-a).
  197.  =======================================================================================================================
  198.  */
  199. #define clip_func(name, sign, dir, dir1, dir2) \
  200.  \
  201.     /* */ \
  202.     static float name(V4 *c, V4 *a, V4 *b) { \
  203.         float    t, dX, dY, dZ, dW, den; \
  204.         dX = (b->X - a->X); \
  205.         dY = (b->Y - a->Y); \
  206.         dZ = (b->Z - a->Z); \
  207.         dW = (b->W - a->W); \
  208.         den = -(sign d ## dir) + dW; \
  209.         if(den == 0) { \
  210.             t = 0; \
  211.         } \
  212.         else { \
  213.             t = (sign a->dir - a->W) / den; \
  214.         } \
  215.  \
  216.         c->dir1 = a->dir1 + t * d ## dir1; \
  217.         c->dir2 = a->dir2 + t * d ## dir2; \
  218.         c->W = a->W + t * dW; \
  219.         c->dir = sign c->W; \
  220.         return t; \
  221.     }
  222.  
  223. clip_func(clip_xmin, -, X, Y, Z)
  224. clip_func(clip_xmax, +, X, Y, Z)
  225. clip_func(clip_ymin, -, Y, X, Z)
  226. clip_func(clip_ymax, +, Y, X, Z)
  227. clip_func(clip_zmin, -, Z, X, Y)
  228. clip_func(clip_zmax, +, Z, X, Y)
  229. float (*clip_proc[6]) (V4 *, V4 *, V4 *) = {
  230.     clip_xmin,
  231.     clip_xmax,
  232.     clip_ymin,
  233.     clip_ymax,
  234.     clip_zmin,
  235.     clip_zmax
  236. };
  237.  
  238. /* */
  239.  
  240. static inline void updateTmp(GLContext *c, GLVertex *q, GLVertex *p0, GLVertex *p1, float t) {
  241.     if(c->current_shade_model == GL_SMOOTH) {
  242.         q->color.v[0] = p0->color.v[0] + (p1->color.v[0] - p0->color.v[0]) * t;
  243.         q->color.v[1] = p0->color.v[1] + (p1->color.v[1] - p0->color.v[1]) * t;
  244.         q->color.v[2] = p0->color.v[2] + (p1->color.v[2] - p0->color.v[2]) * t;
  245.     }
  246.     else {
  247.         q->color.v[0] = p0->color.v[0];
  248.         q->color.v[1] = p0->color.v[1];
  249.         q->color.v[2] = p0->color.v[2];
  250.     }
  251.  
  252.     if(c->texture_2d_enabled) {
  253.         q->tex_coord.X = p0->tex_coord.X + (p1->tex_coord.X - p0->tex_coord.X) * t;
  254.         q->tex_coord.Y = p0->tex_coord.Y + (p1->tex_coord.Y - p0->tex_coord.Y) * t;
  255.     }
  256.  
  257.     q->clip_code = gl_clipcode(q->pc.X, q->pc.Y, q->pc.Z, q->pc.W);
  258.     if(q->clip_code == 0) {
  259.         gl_transform_to_viewport(c, q);
  260.     }
  261. }
  262.  
  263. static void gl_draw_triangle_clip(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2, int clip_bit);
  264.  
  265. /* */
  266.  
  267. void gl_draw_triangle(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2) {
  268.     int        co, c_and, cc[3], front;
  269.     float    norm;
  270.  
  271.     cc[0] = p0->clip_code;
  272.     cc[1] = p1->clip_code;
  273.     cc[2] = p2->clip_code;
  274.  
  275.     co = cc[0] | cc[1] | cc[2];
  276.  
  277.     /* we handle the non clipped case here to go faster */
  278.     if(co == 0) {
  279.         norm = (float) (p1->zp.x - p0->zp.x) * (float) (p2->zp.y - p0->zp.y) - (float) (p2->zp.x - p0->zp.x) * (float) (p1->zp.y - p0->zp.y);
  280.  
  281.         if(norm == 0) {
  282.             return;
  283.         }
  284.  
  285.         front = norm < 0.0;
  286.         front = front ^ c->current_front_face;
  287.  
  288.         /* back face culling */
  289.         if(c->cull_face_enabled) {
  290.             /* most used case first */
  291.             if(c->current_cull_face == GL_BACK) {
  292.                 if(front == 0) {
  293.                     return;
  294.                 }
  295.  
  296.                 c->draw_triangle_front(c, p0, p1, p2);
  297.             }
  298.             else if(c->current_cull_face == GL_FRONT) {
  299.                 if(front != 0) {
  300.                     return;
  301.                 }
  302.  
  303.                 c->draw_triangle_back(c, p0, p1, p2);
  304.             }
  305.             else {
  306.                 return;
  307.             }
  308.         }
  309.         else {
  310.             /* no culling */
  311.             if(front) {
  312.                 c->draw_triangle_front(c, p0, p1, p2);
  313.             }
  314.             else {
  315.                 c->draw_triangle_back(c, p0, p1, p2);
  316.             }
  317.         }
  318.     }
  319.     else {
  320.         c_and = cc[0] & cc[1] & cc[2];
  321.         if(c_and == 0) {
  322.             gl_draw_triangle_clip(c, p0, p1, p2, 0);
  323.         }
  324.     }
  325. }
  326.  
  327. /* */
  328. static void gl_draw_triangle_clip(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2, int clip_bit) {
  329.     int            co, c_and, co1, cc[3], edge_flag_tmp, clip_mask;
  330.     GLVertex    tmp1, tmp2, *q[3];
  331.     float        tt;
  332.  
  333.     cc[0] = p0->clip_code;
  334.     cc[1] = p1->clip_code;
  335.     cc[2] = p2->clip_code;
  336.  
  337.     co = cc[0] | cc[1] | cc[2];
  338.     if(co == 0) {
  339.         gl_draw_triangle(c, p0, p1, p2);
  340.     }
  341.     else {
  342.         c_and = cc[0] & cc[1] & cc[2];
  343.  
  344.         /* the triangle is completely outside */
  345.         if(c_and != 0) {
  346.             return;
  347.         }
  348.  
  349.         /* find the next direction to clip */
  350.         while(clip_bit < 6 && (co & (1 << clip_bit)) == 0) {
  351.             clip_bit++;
  352.         }
  353.  
  354.         /* this test can be true only in case of rounding errors */
  355.         if(clip_bit == 6)
  356.         {
  357. #if 0
  358.             printf("Error:\n");
  359.             printf("%f %f %f %f\n", p0->pc.X, p0->pc.Y, p0->pc.Z, p0->pc.W);
  360.             printf("%f %f %f %f\n", p1->pc.X, p1->pc.Y, p1->pc.Z, p1->pc.W);
  361.             printf("%f %f %f %f\n", p2->pc.X, p2->pc.Y, p2->pc.Z, p2->pc.W);
  362. #endif
  363.             return;
  364.         }
  365.  
  366.         clip_mask = 1 << clip_bit;
  367.         co1 = (cc[0] ^ cc[1] ^ cc[2]) & clip_mask;
  368.  
  369.         if(co1) {
  370.             /* one point outside */
  371.             if(cc[0] & clip_mask) {
  372.                 q[0] = p0;
  373.                 q[1] = p1;
  374.                 q[2] = p2;
  375.             }
  376.             else if(cc[1] & clip_mask) {
  377.                 q[0] = p1;
  378.                 q[1] = p2;
  379.                 q[2] = p0;
  380.             }
  381.             else {
  382.                 q[0] = p2;
  383.                 q[1] = p0;
  384.                 q[2] = p1;
  385.             }
  386.  
  387.             tt = clip_proc[clip_bit](&tmp1.pc, &q[0]->pc, &q[1]->pc);
  388.             updateTmp(c, &tmp1, q[0], q[1], tt);
  389.  
  390.             tt = clip_proc[clip_bit](&tmp2.pc, &q[0]->pc, &q[2]->pc);
  391.             updateTmp(c, &tmp2, q[0], q[2], tt);
  392.  
  393.             tmp1.edge_flag = q[0]->edge_flag;
  394.             edge_flag_tmp = q[2]->edge_flag;
  395.             q[2]->edge_flag = 0;
  396.             gl_draw_triangle_clip(c, &tmp1, q[1], q[2], clip_bit + 1);
  397.  
  398.             tmp2.edge_flag = 1;
  399.             tmp1.edge_flag = 0;
  400.             q[2]->edge_flag = edge_flag_tmp;
  401.             gl_draw_triangle_clip(c, &tmp2, &tmp1, q[2], clip_bit + 1);
  402.         }
  403.         else {
  404.             /* two points outside */
  405.             if((cc[0] & clip_mask) == 0) {
  406.                 q[0] = p0;
  407.                 q[1] = p1;
  408.                 q[2] = p2;
  409.             }
  410.             else if((cc[1] & clip_mask) == 0) {
  411.                 q[0] = p1;
  412.                 q[1] = p2;
  413.                 q[2] = p0;
  414.             }
  415.             else {
  416.                 q[0] = p2;
  417.                 q[1] = p0;
  418.                 q[2] = p1;
  419.             }
  420.  
  421.             tt = clip_proc[clip_bit](&tmp1.pc, &q[0]->pc, &q[1]->pc);
  422.             updateTmp(c, &tmp1, q[0], q[1], tt);
  423.  
  424.             tt = clip_proc[clip_bit](&tmp2.pc, &q[0]->pc, &q[2]->pc);
  425.             updateTmp(c, &tmp2, q[0], q[2], tt);
  426.  
  427.             tmp1.edge_flag = 1;
  428.             tmp2.edge_flag = q[2]->edge_flag;
  429.             gl_draw_triangle_clip(c, q[0], &tmp1, &tmp2, clip_bit + 1);
  430.         }
  431.     }
  432. }
  433.  
  434. /* */
  435. void gl_draw_triangle_select(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2) {
  436.     gl_add_select1(c, p0->zp.z, p1->zp.z, p2->zp.z);
  437. }
  438.  
  439. #ifdef PROFILE
  440. int count_triangles, count_triangles_textured, count_pixels;
  441. #endif
  442.  
  443. /* */
  444. void gl_draw_triangle_fill(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2)
  445. {
  446. #ifdef PROFILE 
  447.     {
  448.         int norm;
  449.         assert(p0->zp.x >= 0 && p0->zp.x < c->zb->xsize);
  450.         assert(p0->zp.y >= 0 && p0->zp.y < c->zb->ysize);
  451.         assert(p1->zp.x >= 0 && p1->zp.x < c->zb->xsize);
  452.         assert(p1->zp.y >= 0 && p1->zp.y < c->zb->ysize);
  453.         assert(p2->zp.x >= 0 && p2->zp.x < c->zb->xsize);
  454.         assert(p2->zp.y >= 0 && p2->zp.y < c->zb->ysize);
  455.  
  456.         norm = (p1->zp.x - p0->zp.x) * (p2->zp.y - p0->zp.y) - (p2->zp.x - p0->zp.x) * (p1->zp.y - p0->zp.y);
  457.         count_pixels += abs(norm) / 2;
  458.         count_triangles++;
  459.     }
  460. #endif
  461.     if(c->texture_2d_enabled)
  462.     {
  463. #ifdef PROFILE
  464.         count_triangles_textured++;
  465. #endif
  466.         ZB_setTexture(c->zb, c->current_texture->images[0].pixmap);
  467.         ZB_fillTriangleMappingPerspective(c->zb, &p0->zp, &p1->zp, &p2->zp);
  468.     }
  469.     else if(c->current_shade_model == GL_SMOOTH) {
  470.         if (c->blending_enabled) {
  471.             ZB_fillTriangleSmoothBlend(c->zb, &p0->zp, &p1->zp, &p2->zp, c->current_color.W);
  472.         }
  473.         else {
  474.             ZB_fillTriangleSmooth(c->zb, &p0->zp, &p1->zp, &p2->zp);
  475.         }
  476.     }
  477.     else {
  478.         if (c->blending_enabled) {
  479.             ZB_fillTriangleFlatBlend(c->zb, &p0->zp, &p1->zp, &p2->zp, c->current_color.W);
  480.         }
  481.         else {
  482.             ZB_fillTriangleFlat(c->zb, &p0->zp, &p1->zp, &p2->zp);
  483.         }
  484.     }
  485. }
  486.  
  487. /* Render a clipped triangle in line mode */
  488. void gl_draw_triangle_line(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2) {
  489.     if(c->depth_test) {
  490.         if(p0->edge_flag) {
  491.             ZB_line_z(c->zb, &p0->zp, &p1->zp);
  492.         }
  493.  
  494.         if(p1->edge_flag) {
  495.             ZB_line_z(c->zb, &p1->zp, &p2->zp);
  496.         }
  497.  
  498.         if(p2->edge_flag) {
  499.             ZB_line_z(c->zb, &p2->zp, &p0->zp);
  500.         }
  501.     }
  502.     else {
  503.         if(p0->edge_flag) {
  504.             ZB_line(c->zb, &p0->zp, &p1->zp);
  505.         }
  506.  
  507.         if(p1->edge_flag) {
  508.             ZB_line(c->zb, &p1->zp, &p2->zp);
  509.         }
  510.  
  511.         if(p2->edge_flag) {
  512.             ZB_line(c->zb, &p2->zp, &p0->zp);
  513.         }
  514.     }
  515. }
  516.  
  517. /* Render a clipped triangle in point mode */
  518. void gl_draw_triangle_point(GLContext *c, GLVertex *p0, GLVertex *p1, GLVertex *p2) {
  519.     if(p0->edge_flag) {
  520.         ZB_plot(c->zb, &p0->zp);
  521.     }
  522.  
  523.     if(p1->edge_flag) {
  524.         ZB_plot(c->zb, &p1->zp);
  525.     }
  526.  
  527.     if(p2->edge_flag) {
  528.         ZB_plot(c->zb, &p2->zp);
  529.     }
  530. }
  531.